Skip to content

[Components] attio - added new components #16411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 5, 2025
Merged

Conversation

jcortes
Copy link
Collaborator

@jcortes jcortes commented Apr 23, 2025

WHY

Resolves #16302

Summary by CodeRabbit

  • New Features

    • Added actions for creating and updating person records, creating tasks, creating notes, and deleting list entries in Attio.
    • Introduced a new event source for instant detection of new notes, tasks, or comments.
    • Added new constants to enhance API integration and resource targeting.
  • Improvements

    • Improved property selection, labeling, and input flexibility for record creation and updates.
    • Unified event subscription interfaces by replacing separate event type and filter methods with subscription objects across all instant event sources.
    • Enhanced webhook management with new dedicated creation and deletion methods.
    • Refined API method calls and property definitions for better modularity and consistency.
    • Updated utility functions to support dynamic property generation and metadata handling.
  • Bug Fixes

    • Updated versioning and summary message formats for actions and event sources.

@jcortes jcortes self-assigned this Apr 23, 2025
Copy link

vercel bot commented Apr 23, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Ignored (Inspect) Visit Preview May 5, 2025 8:09pm
pipedream-docs ⬜️ Ignored (Inspect) May 5, 2025 8:09pm
pipedream-docs-redirect-do-not-edit ⬜️ Ignored (Inspect) May 5, 2025 8:09pm

Copy link
Contributor

coderabbitai bot commented Apr 23, 2025

Walkthrough

This update introduces significant enhancements and refactoring to the Attio integration components. It adds new actions for creating and updating person records, as well as creating tasks. The webhook source system is refactored to use a new subscription-based event declaration, replacing the previous event type and filter methods. A new source is added to emit events for new activities (notes, tasks, comments). The Attio app is refactored for modularity, with expanded property definitions and unified HTTP request handling. Supporting constants are centralized in a new module, and multiple component versions are incremented to reflect these changes.

Changes

File(s) Change Summary
components/attio/actions/create-person/create-person.mjs
components/attio/actions/update-person/update-person.mjs
components/attio/actions/create-task/create-task.mjs
New action modules for creating and updating people and tasks in Attio, implementing API payload construction and submission logic.
components/attio/actions/create-note/create-note.mjs
components/attio/actions/delete-list-entry/delete-list-entry.mjs
Refactored to use new method wrappers for API calls, updated property definitions, and improved parameter mapping.
components/attio/actions/create-update-record/create-update-record.mjs Updated version and modified matching attribute props and logic for record upsert.
components/attio/attio.app.mjs Major refactor: expanded propDefinitions for person fields, added async option loaders, unified HTTP request methods, improved modularity, and updated API endpoint usage.
components/attio/common/constants.mjs New module introducing constants for API base URL, version path, default limit, and target object types.
components/attio/package.json Package version updated from 0.2.0 to 0.3.0.
components/attio/sources/common/base.mjs Refactored webhook management: replaced event type/filter methods with subscription-based method, encapsulated webhook creation/deletion logic.
components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs
components/attio/sources/new-activity-created-instant/test-event.mjs
New source for emitting events on note, task, or comment creation, with sample event for testing.
components/attio/sources/new-note-instant/new-note-instant.mjs
components/attio/sources/note-updated-instant/note-updated-instant.mjs
components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs
components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs
Updated from single event type method to new subscription-based event declaration; version increments.
components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs
components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs
components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs
components/attio/sources/new-record-created-instant/new-record-created-instant.mjs
components/attio/sources/record-updated-instant/record-updated-instant.mjs
Replaced getEventType/getFilter methods with getSubscriptions, encapsulating event type and filter in a unified structure; version updates.
components/attio/common/utils.mjs Removed parseValues function; added new utility functions for generating metadata and dynamic property definitions for fields.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AttioAction
    participant AttioApp
    participant AttioAPI

    User->>AttioAction: Trigger "Create Person" or "Update Person" or "Create Task"
    AttioAction->>AttioApp: Call createRecord/updateRecord/postTask with user data
    AttioApp->>AttioAPI: Send HTTP POST/PATCH to Attio endpoint
    AttioAPI-->>AttioApp: Return API response
    AttioApp-->>AttioAction: Return result
    AttioAction-->>User: Output summary and data
Loading
sequenceDiagram
    participant SourceComponent
    participant BaseSource
    participant AttioApp
    participant AttioAPI

    SourceComponent->>BaseSource: Activate (subscribe to events)
    BaseSource->>AttioApp: createWebhook with subscriptions
    AttioApp->>AttioAPI: POST /webhooks
    AttioAPI-->>AttioApp: Webhook confirmation
    AttioApp-->>BaseSource: Webhook created
    BaseSource-->>SourceComponent: Ready to receive events
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement webhook source for "new-activity-instant" to emit events on note, task, or comment creation (#16302)
Implement "create-person" action with required name and email, optional company, tags, custom fields (#16302)
Implement "update-person" action to update person info by ID, supporting optional fields (#16302)
Implement "create-task" action for creating tasks for a person record (#16302)

Suggested labels

User submitted

Poem

In the warren of code, a hop and a dash,
New people and tasks join in a flash!
Webhooks now listen, with ears tall and keen,
For notes, tasks, and comments—on every new scene.
Constants are gathered, requests unified—
This rabbit’s delighted, with whiskers of pride!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

components/attio/actions/create-note/create-note.mjs

Oops! Something went wrong! :(

ESLint: 8.57.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

components/attio/actions/create-person/create-person.mjs

Oops! Something went wrong! :(

ESLint: 8.57.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

components/attio/actions/create-task/create-task.mjs

Oops! Something went wrong! :(

ESLint: 8.57.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

  • 18 others

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef5b37d and a528d04.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • components/attio/actions/create-note/create-note.mjs (3 hunks)
  • components/attio/actions/create-person/create-person.mjs (1 hunks)
  • components/attio/actions/create-task/create-task.mjs (1 hunks)
  • components/attio/actions/create-update-record/create-update-record.mjs (2 hunks)
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs (2 hunks)
  • components/attio/actions/update-person/update-person.mjs (1 hunks)
  • components/attio/attio.app.mjs (2 hunks)
  • components/attio/common/constants.mjs (1 hunks)
  • components/attio/common/utils.mjs (2 hunks)
  • components/attio/package.json (1 hunks)
  • components/attio/sources/common/base.mjs (3 hunks)
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs (2 hunks)
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs (2 hunks)
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (1 hunks)
  • components/attio/sources/new-activity-created-instant/test-event.mjs (1 hunks)
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs (2 hunks)
  • components/attio/sources/new-note-instant/new-note-instant.mjs (1 hunks)
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs (1 hunks)
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs (2 hunks)
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs (1 hunks)
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs (1 hunks)
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/attio/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (19)
  • components/attio/package.json
  • components/attio/sources/new-activity-created-instant/test-event.mjs
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs
  • components/attio/sources/new-note-instant/new-note-instant.mjs
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs
  • components/attio/sources/common/base.mjs
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs
  • components/attio/actions/create-task/create-task.mjs
  • components/attio/actions/update-person/update-person.mjs
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs
  • components/attio/actions/create-note/create-note.mjs
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs
  • components/attio/actions/create-person/create-person.mjs
  • components/attio/actions/create-update-record/create-update-record.mjs
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (13)
components/attio/common/utils.mjs (5)

1-2: Added constant import for code organization.

Good addition of a central constants import, which helps maintain consistent configuration values across the component.


38-41: LGTM: Good string utility function.

The toPascalCase function correctly converts strings to PascalCase format, which will be helpful for consistent field naming throughout the component.


43-56: LGTM: Clear metadata structure generation.

This function creates a standardized way to generate metadata properties with appropriate prefixes and labels, which improves consistency across the component.


88-122: LGTM: Well-structured async property generation.

This function provides a clean way to generate additional property definitions asynchronously, using a flexible reducer pattern to build property definitions dynamically.


127-131: LGTM: Updated exports to include new utility functions.

Correctly exports all the newly added utility functions, making them available for use in other components.

components/attio/attio.app.mjs (8)

2-2: LGTM: Improved code organization with constants import.

Good refactoring to import constants from a dedicated module, which centralizes configuration values.


8-71: LGTM: Comprehensive person property definitions.

These well-structured property definitions provide a complete set of fields for person records, with appropriate types, labels, and descriptions.


105-122: LGTM: Well-structured workspace member lookup.

Good implementation of workspace member retrieval with appropriate mapping to display formatted names.


130-131: Updated property options methods with consistent formatting

Good refactoring of the options methods to use consistent data extraction and filtering patterns.

Also applies to: 148-149, 151-151, 161-165, 182-183, 186-191


197-205: LGTM: Clean URL and header handling.

Good encapsulation of URL construction and header handling in dedicated methods, which improves maintainability.


207-214: LGTM: Improved request parameter handling.

Better parameter destructuring and default values in the request method.


215-238: LGTM: Unified HTTP method wrappers.

Good refactoring to add generic HTTP method wrappers that simplify API calls throughout the component.


239-304: LGTM: Comprehensive API methods with consistent parameter handling.

These API methods provide a clean interface for interacting with the Attio API using the HTTP method wrappers. Good use of destructuring to extract and forward parameters.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
components/attio/attio.app.mjs (1)

141-152: 🛠️ Refactor suggestion

Repeat the safe‑offset fix in every loader that paginates

To keep behaviour consistent, apply the page ?? 0 guard (or default
page = 0 in the parameter list) to:

  • entryId.options() – lines 147‑149
  • attributeId.options() – lines 180‑182

Otherwise the first‑page lookup for those selectors can break.
Happy to open a small follow‑up PR if you like.

Also applies to: 177-183

🧹 Nitpick comments (9)
components/attio/actions/create-task/create-task.mjs (1)

16-20: Consider adding date validation for deadline

While the description explains the ISO 8601 format requirement, consider adding validation to ensure the provided date string is valid.

 deadlineAt: {
   type: "string",
   label: "Deadline",
   description: "The deadline of the task in ISO 8601 format (e.g. `2025-04-22T10:00:00Z`)",
+  validate: (value) => {
+    if (!value) return true;
+    const date = new Date(value);
+    return !isNaN(date.getTime()) || "Please provide a valid ISO 8601 date string";
+  },
 },
components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (2)

9-9: Consider starting with version 0.0.1.

The component is using version 0.0.3 despite being newly introduced. Usually, new components start with version 0.0.1 and increment as changes are made.

-  version: "0.0.3",
+  version: "0.0.1",

30-36: Consider extracting repeated ID logic to a helper method.

The same ID extraction logic is repeated three times in this method. Consider extracting it to improve readability and maintainability.

  generateMeta(record) {
+   const activityId = record.id.task_id || record.id.note_id || record.id.comment_id;
    return {
-     id: record.id.task_id || record.id.note_id || record.id.comment_id,
-     summary: `New Activity with ID: ${record.id.task_id || record.id.note_id || record.id.comment_id}`,
+     id: activityId,
+     summary: `New Activity with ID: ${activityId}`,
      ts: Date.now(),
    };
  },
components/attio/actions/update-person/update-person.mjs (1)

110-218: Consider shared utilities for common person record operations.

This component shares significant code with the create-person action. Consider extracting the common data structuring logic into a shared utility function to improve maintainability.

You could create a utility function in a common module that takes person fields and returns the structured data object, which both actions could then use.

components/attio/attio.app.mjs (5)

196-204: Expose Accept and Content‑Type defaults in one place

getHeaders() hard‑codes only Authorization. Every Attio endpoint
expects JSON, so callers must remember to pass
headers: { "Content-Type": "application/json" } each time. Consider
centralising the two defaults:

   getHeaders(headers) {
     return {
       ...headers,
+      "Accept": "application/json",
+      "Content-Type": "application/json",
       "Authorization": `Bearer ${this.$auth.oauth_access_token}`,
     };
   },

This removes repetition in the new action components.


214-237: Method priority allows accidental override of HTTP verb

The helpers (post, patch, put, delete) spread ...args after
the hard‑coded method, letting callers silently override the verb.
A typo such as this.post({ method: "GET", … }) would send a GET but
be named “post”, confusing for readers and log inspection.

Move method to the end to make it authoritative:

-    post(args = {}) {
-      return this._makeRequest({
-        method: "POST",
-        ...args,
-      });
+    post(args = {}) {
+      return this._makeRequest({
+        ...args,
+        method: "POST",
+      });
     },

Repeat for the other three helpers.


48-71: Social profile props could share a single reusable definition

linkedin, twitter, facebook, and instagram are structurally
identical. Duplicating them bloats the component and invites
inconsistent edits later. A small helper cuts the noise:

const socialProp = (platform, label = platform) => ({
  type: "string",
  label: label.charAt(0).toUpperCase() + label.slice(1),
  description: `The person's ${label} profile URL.`,
  optional: true,
});

linkedin: socialProp("linkedin"),
twitter: socialProp("twitter", "Twitter handle"),
facebook: socialProp("facebook"),
instagram: socialProp("instagram"),

Not mandatory, but keeps the file readable as more fields are added.


124-135: Return { label, value } objects for better UX

The listId and entryId loaders currently return bare strings for the
value, relying on Pipedream to auto‑label. Returning explicit objects
gives users readable dropdowns immediately — especially helpful for
entryId, which today shows only UUIDs.

-return data?.map(({ id: { entry_id: value } }) => value) || [];
+return data?.map(({ id: { entry_id: value } }) => ({
+  label: value,
+  value,
+})) || [];

Applies similarly to entryId and any other loader that returns raw
IDs.


238-243: Add pagination to listWorkspaceMembers

Large workspaces can have hundreds of members; the current call fetches
only the default page. The Attio API supports limit/offset, so
expose page in the options loader and reuse the existing pagination
pattern.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 106b401 and ae31376.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • components/attio/actions/create-note/create-note.mjs (3 hunks)
  • components/attio/actions/create-person/create-person.mjs (1 hunks)
  • components/attio/actions/create-task/create-task.mjs (1 hunks)
  • components/attio/actions/create-update-record/create-update-record.mjs (1 hunks)
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs (2 hunks)
  • components/attio/actions/update-person/update-person.mjs (1 hunks)
  • components/attio/attio.app.mjs (3 hunks)
  • components/attio/common/constants.mjs (1 hunks)
  • components/attio/package.json (1 hunks)
  • components/attio/sources/common/base.mjs (3 hunks)
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs (2 hunks)
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs (2 hunks)
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (1 hunks)
  • components/attio/sources/new-activity-created-instant/test-event.mjs (1 hunks)
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs (2 hunks)
  • components/attio/sources/new-note-instant/new-note-instant.mjs (1 hunks)
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs (1 hunks)
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs (2 hunks)
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs (1 hunks)
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs (1 hunks)
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
components/attio/sources/common/base.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Lint Code Base
  • GitHub Check: Verify TypeScript components
🔇 Additional comments (46)
components/attio/common/constants.mjs (1)

1-18: Well-structured constants module for Attio API integration

This new constants module effectively centralizes important API configuration values like base URL, version path, and pagination limits. The TARGET_OBJECT enum provides a clean way to reference object types throughout the codebase.

This approach follows best practices by:

  1. Eliminating hardcoded values across the integration
  2. Creating a single source of truth for API configuration
  3. Making future API endpoint or configuration changes easier to maintain
components/attio/sources/common/base.mjs (4)

11-15: Good refactoring of webhook activation with subscription-based model

The webhook activation method now uses the new createWebhook wrapper and a subscription-based model via getSubscriptions() instead of separate event type and filter methods. This approach is more modular and follows the pattern used in other Pipedream integrations.


22-27: Good refactoring of webhook deactivation with wrapper method

The deactivation hook now uses the new deleteWebhook wrapper method, which is consistent with the modular approach applied to the activation hook.


37-39: Abstract method correctly implemented

Replacing the previous abstract methods with a single getSubscriptions() method follows good object-oriented design principles. The error message correctly indicates that subclasses must implement this method.


43-56: Well-implemented webhook wrapper methods

The new createWebhook and deleteWebhook methods properly encapsulate the API calls to create and delete webhooks. They cleanly use the app's HTTP methods and handle path construction. This approach:

  1. Centralizes webhook management logic
  2. Makes the code more maintainable
  3. Follows the DRY principle by avoiding repetition in derived classes
components/attio/package.json (1)

3-3: Appropriate version bump for feature additions

Incrementing the package version from 0.2.0 to 0.3.0 is appropriate given the significant additions (new components for creating/updating persons and tasks) and refactoring (webhook subscription model) in this PR.

components/attio/actions/create-update-record/create-update-record.mjs (1)

8-8: Version incremented for consistency

The action version has been incremented from "0.0.2" to "0.0.3", which maintains version consistency with other updated Attio components in this PR.

components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs (1)

9-21: Clean architectural improvement for webhook subscription management

The version increment and refactoring from getEventType() to the new getSubscriptions() method aligns with the broader architectural updates in the Attio integration. This new pattern provides more flexibility by allowing multiple subscriptions if needed in the future, and creates a more consistent approach across all source components.

components/attio/sources/note-updated-instant/note-updated-instant.mjs (1)

9-21: Consistent implementation of the subscription pattern

Good job maintaining consistency with the architectural pattern change. The version increment and implementation of the new getSubscriptions() method follows the same structure as other Attio source components, making the codebase more cohesive and easier to maintain.

components/attio/sources/new-activity-created-instant/test-event.mjs (1)

1-16: Well-structured test event for the new activity source

This test event provides a good representation of an Attio webhook payload for task creation events. The structure includes all necessary fields (webhook_id, event_type, workspace_id, task_id, and actor details), making it valuable for testing the new activity source component.

components/attio/sources/new-note-instant/new-note-instant.mjs (1)

9-21: Systematic application of the new subscription pattern

The version increment and replacement of getEventType() with the new getSubscriptions() method demonstrates a systematic approach to refactoring the Attio integration. This consistent implementation across all source components will make future maintenance and enhancements easier.

components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs (2)

9-9: Version bump is appropriate

The version increment from 0.0.1 to 0.0.2 is appropriate for this change since you're modifying the component's interface without changing its core functionality.


14-21: Good refactoring of event subscription

The new getSubscriptions() method effectively replaces the previous getEventType() method, returning a structured subscription object instead. This approach is more flexible as it allows for multiple subscriptions if needed in the future.

components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs (2)

9-9: Version bump is appropriate

The version increment from 0.0.1 to 0.0.2 is appropriate for this change since you're modifying the component's interface without changing its core functionality.


23-38: Good refactoring of event subscription and filter

The new getSubscriptions() method effectively combines the previous getEventType() and getFilter() methods into a single, more structured approach. This unification makes the code more maintainable and aligns with the refactoring pattern applied across other Attio components.

components/attio/sources/new-record-created-instant/new-record-created-instant.mjs (2)

9-9: Version bump is appropriate

The version increment from 0.0.2 to 0.0.3 is appropriate for this change since you're modifying the component's interface without changing its core functionality.


23-38: Good refactoring of event subscription and filter

The new getSubscriptions() method effectively combines the previous getEventType() and getFilter() methods into a single, more structured approach. This makes the component consistent with the broader refactoring pattern across Attio source components.

components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs (2)

9-9: Version bump is appropriate

The version increment from 0.0.2 to 0.0.3 is appropriate for this change since you're modifying the component's interface without changing its core functionality.


23-38: Good refactoring of event subscription and filter

The new getSubscriptions() method effectively combines the previous getEventType() and getFilter() methods into a single, more structured approach. This unification improves consistency across components and enables more flexible subscription management.

components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs (2)

9-9: Appropriate version increment

Version has been correctly updated from 0.0.1 to 0.0.2 to reflect the interface changes in how webhook subscriptions are handled.


23-38: Good refactoring to unified subscription model

The change from separate getEventType() and getFilter() methods to a single getSubscriptions() method improves modularity and aligns with the broader refactoring across multiple Attio source components. The subscription structure is well-organized and maintains the same filtering logic.

components/attio/actions/create-task/create-task.mjs (2)

1-71: Well-structured new action component

This new "Create Task" action follows best practices for Pipedream components with clear prop definitions, appropriate documentation links, and concise methods. The component correctly implements the Attio API for task creation.


60-63: Good handling of optional assignees

The code correctly handles the case where assigneeIds might be undefined by using optional chaining and providing an empty array fallback.

components/attio/actions/delete-list-entry/delete-list-entry.mjs (4)

7-7: Appropriate version increment

Version has been correctly updated from 0.0.2 to 0.0.3 to reflect the interface changes in the component.


21-23: Improved parameter destructuring

The simplification of the propDefinition callback with direct destructuring improves code readability.


27-36: Good modularization with dedicated API method

Adding a dedicated deleteListEntry method improves code organization and follows the pattern used in other components. The method correctly constructs the API path and forwards additional options.


38-42: Clean method invocation

Run method now correctly uses the new dedicated method instead of directly calling the app's method, which is consistent with the overall refactoring approach.

components/attio/sources/record-updated-instant/record-updated-instant.mjs (2)

9-9: Appropriate version increment

Version has been correctly updated from 0.0.2 to 0.0.3 to reflect the interface changes in how webhook subscriptions are handled.


23-38: Good refactoring to unified subscription model

The change from separate methods to a single getSubscriptions() method improves consistency and aligns with the broader refactoring across Attio source components. The subscription structure effectively maintains the same filtering logic while providing a more organized approach to webhook event handling.

components/attio/actions/create-note/create-note.mjs (7)

7-7: Version increment looks appropriate.

The version has been incremented from 0.0.2 to 0.0.3, which is appropriate given the refactoring and improvements made to this component.


15-23: Good enhancement to the parentObject prop.

The mapper function provides better UX by converting API values to more user-friendly display formats. This improves the component's usability by showing meaningful labels to users instead of raw API values.


25-26: Improved prop labeling.

The updated label and description are more clear and consistent with other components in the integration.


32-33: Improved parameter naming.

Changing from objectId to targetObject provides better semantic clarity about what the parameter represents.


50-57: Good modularization with methods object.

Extracting API call logic into a dedicated method improves code organization and maintainability. This approach also makes the component more consistent with other Attio components.


59-59: Refactored to use the dedicated createNote method.

This change makes the code more maintainable by centralizing the API call logic in the methods section.


71-71: Improved summary formatting.

Using backticks around the ID improves readability in the output, making it easier to distinguish the ID from the rest of the text.

components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (2)

4-11: Nice addition of a unified activity source.

This new component efficiently handles multiple activity types (notes, tasks, comments) in a single source, which provides a more streamlined way to track engagement activities.


14-29: Well-structured subscription method.

The getSubscriptions method clearly defines all the event types to listen for without any filters, making it easy to understand what events this source will emit.

components/attio/actions/update-person/update-person.mjs (3)

4-9: Great addition of an update person action.

This well-structured action provides comprehensive options for updating existing person records in Attio.


12-29: Well-designed recordId prop with custom mapper.

The prop definition with custom mapper enhances usability by displaying meaningful person names instead of just IDs in the dropdown.


129-214: Well-structured conditional data payload.

The approach of conditionally including fields only when they're provided is clean and efficient. The nested structure correctly follows the Attio API's expected format.

components/attio/actions/create-person/create-person.mjs (5)

4-9: Great addition of a create person action.

This well-structured action provides comprehensive options for creating new person records in Attio.


12-89: Well-organized props definitions.

The props are well-organized with appropriate labels, descriptions, and leveraging reusable prop definitions from the Attio app.


108-193: Well-structured API call with conditional data fields.

The approach of conditionally including fields only when they're provided is clean and efficient. The structure correctly follows the Attio API's expected format.


195-195: Good use of backticks in summary message.

Using backticks around the ID improves readability in the output, making it easier to distinguish the ID from the rest of the text.


121-121: ⚠️ Potential issue

Fix syntax error in conditional spread operator.

There's a missing parenthesis in the logical condition that could cause unexpected behavior.

-            ...(firstName || lastName) && {
+            ...((firstName || lastName) && {

Likely an incorrect or invalid review comment.

luancazarine
luancazarine previously approved these changes Apr 28, 2025
Copy link
Collaborator

@luancazarine luancazarine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jcortes I just added a minor suggestion. But I'm moving it to Ready for QA anyway

@jcortes jcortes force-pushed the attio-new-components branch 2 times, most recently from 14a9d5b to 8861d86 Compare April 30, 2025 20:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
components/attio/attio.app.mjs (1)

72-104: Fix potential NaN in offset calculation

In the recordId options function, the offset calculation can result in NaN if page is undefined.

        data: {
          limit: constants.DEFAULT_LIMIT,
-         offset: page * constants.DEFAULT_LIMIT,
+         offset: (page ?? 0) * constants.DEFAULT_LIMIT,
🧹 Nitpick comments (6)
components/attio/actions/create-task/create-task.mjs (3)

46-56: Consider adding validation for linked record properties

The linkedRecordPropsMapper method assumes that this[${prefix}targetObject] and this[${prefix}targetRecordId] exist, but there's no validation to handle cases where they might be undefined.

 linkedRecordPropsMapper(prefix) {
   const {
     [`${prefix}targetObject`]: targetObject,
     [`${prefix}targetRecordId`]: targetRecordId,
   } = this;

+  if (!targetObject || !targetRecordId) {
+    return {};
+  }

   return {
     target_object: targetObject,
     target_record_id: targetRecordId,
   };
 },

57-103: Enhance record label fallback for better UX

In the getLinkedRecordsPropDefinitions method, there's a risk of displaying "undefined" labels if the name array exists but has no valid values.

 targetRecordOptions = data.map(({
   id: { record_id: value },
   values: { name },
 }) => ({
   value,
-  label: name[0]?.value || name[0]?.full_name || "unknown",
+  label: name && (name[0]?.value || name[0]?.full_name) || `Record ${value}`,
 }));

123-156: Run method is well-structured but could use error handling

The method effectively collects inputs, transforms them to the API format, and makes the API call. The export summary provides good feedback to the user.

Consider adding error handling to improve robustness:

 async run({ $ }) {
   const {
     content,
     deadlineAt,
     isCompleted,
     assigneeIds,
     numberOfLinkedRecords,
     linkedRecordPropsMapper,
   } = this;

+  try {
     const response = await this.createTask({
       $,
       data: {
         data: {
           format: "plaintext",
           content,
           deadline_at: deadlineAt,
           is_completed: isCompleted,
           assignees: assigneeIds?.map((id) => ({
             referenced_actor_type: "workspace-member",
             referenced_actor_id: id,
           })) || [],
           linked_records: utils.getFieldsProps({
             numberOfFields: numberOfLinkedRecords,
             fieldName: "linked record",
             propsMapper: linkedRecordPropsMapper,
           }),
         },
       },
     });

     $.export("$summary", `Successfully created task with ID \`${response.data.id.task_id}\`.`);
     return response;
+  } catch (error) {
+    $.export("error", error);
+    throw `Failed to create task: ${error.message}`;
+  }
 },
components/attio/actions/create-update-record/create-update-record.mjs (2)

55-87: Remove commented-out code

The commented-out parseValues function and filtering logic should be removed to keep the codebase clean.

-    // parseValues(attributes, values) {
-    //   for (const [
-    //     key,
-    //     value,
-    //   ] of Object.entries(values)) {
-    //     const {
-    //       type, is_multiselect: isMultiselect,
-    //     } = attributes.find(({ id }) => id.attribute_id === key);
-    //     if (type === "checkbox") {
-    //       values[key] = isMultiselect
-    //         ? value.map((v) => !(v === "false" || v === "0"))
-    //         : !(value === "false" || value === "0");
-    //     }
-    //     if (type === "number" || type === "rating") {
-    //       values[key] = isMultiselect
-    //         ? value.map((v) => +v)
-    //         : +value;
-    //     }
-    //   }
-    //   return values;
-    // },
    async getRelevantAttributes() {
      const stream = utils.paginate({
        fn: this.attio.listAttributes,
        args: {
          objectId: this.objectId,
        },
      });
      const attributes = await utils.streamIterator(stream);
      return attributes.filter((a) => a.is_writable);
-      // return attributes.filter((a) =>
-      //   a.is_writable || (includeAttrId && a.id.attribute_id === this.attributeId));
    },

89-103: Remove debugging console.log statement

There's a console.log statement that should be removed before production.

  async run({ $ }) {
    const {
      attio,
-      // parseValues,
-      // getRelevantAttributes,
      objectId,
      matchingAttribute,
      matchingAttributeValue,
      ...values
    } = this;

-    // const attributes = await getRelevantAttributes();
-
-    console.log("values!!!", JSON.stringify(values, null, 2));
components/attio/attio.app.mjs (1)

105-122: Improve workspaceMember label handling

The workspaceMemberId options function could produce labels with extra spaces if firstName or lastName are undefined.

        }) => ({
          value,
-         label: `${firstName || ""} ${lastName || ""}`.trim(),
+         label: [firstName, lastName].filter(Boolean).join(" ") || `Member ${value}`,
        }),
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14a9d5b and 8861d86.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • components/attio/actions/create-note/create-note.mjs (3 hunks)
  • components/attio/actions/create-person/create-person.mjs (1 hunks)
  • components/attio/actions/create-task/create-task.mjs (1 hunks)
  • components/attio/actions/create-update-record/create-update-record.mjs (4 hunks)
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs (2 hunks)
  • components/attio/actions/update-person/update-person.mjs (1 hunks)
  • components/attio/attio.app.mjs (3 hunks)
  • components/attio/common/constants.mjs (1 hunks)
  • components/attio/common/utils.mjs (2 hunks)
  • components/attio/package.json (1 hunks)
  • components/attio/sources/common/base.mjs (3 hunks)
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs (2 hunks)
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs (2 hunks)
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (1 hunks)
  • components/attio/sources/new-activity-created-instant/test-event.mjs (1 hunks)
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs (2 hunks)
  • components/attio/sources/new-note-instant/new-note-instant.mjs (1 hunks)
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs (1 hunks)
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs (2 hunks)
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs (1 hunks)
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs (1 hunks)
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/attio/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (17)
  • components/attio/package.json
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs
  • components/attio/sources/new-note-instant/new-note-instant.mjs
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs
  • components/attio/actions/update-person/update-person.mjs
  • components/attio/sources/common/base.mjs
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs
  • components/attio/actions/create-note/create-note.mjs
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs
  • components/attio/sources/new-activity-created-instant/test-event.mjs
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs
  • components/attio/actions/create-person/create-person.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
🔇 Additional comments (21)
components/attio/actions/create-task/create-task.mjs (4)

1-4: Well-structured imports

The imports are clear and well-organized, following a logical structure by importing the app module first, followed by constants and utilities.


5-44: Component definition and props look good

The action is well-defined with appropriate metadata and clear property definitions. The properties have descriptive labels and helpful descriptions. Good job implementing the dynamic linked records functionality with numberOfLinkedRecords and reloadProps: true.


104-109: LGTM - Simple and clean task creation method

The createTask method is well-implemented, using the app's POST method with the correct path and passing through any additional arguments.


111-122: Well-implemented dynamic props generation

The additionalProps method effectively leverages the utility functions to generate dynamic linked record properties based on the specified count. This is a clean implementation of dynamic property generation.

components/attio/common/utils.mjs (6)

1-2: Clean import of constants

Good job centralizing constants in a separate module and importing them here.


38-41: Nice utility for PascalCase conversion

The toPascalCase function is well-implemented using regex for string transformation, making it reusable across the codebase.


43-56: Well-structured metadata property generator

The getMetadataProp function effectively handles prefixes and labels with clean conditional expressions.


75-86: LGTM - Clean implementation of fields props generator

The getFieldsProps function provides a clean way to generate multiple field properties using Array mapping.


88-122: Async property generator is well-implemented

The getAdditionalProps function effectively handles async operations with proper await chaining. The reduction pattern ensures props are accumulated correctly as promises resolve.


124-131: LGTM - Clean exports

All utility functions are properly exported for reuse throughout the codebase.

components/attio/actions/create-update-record/create-update-record.mjs (4)

8-8: Significant version increment

The version has been updated from 0.0.2 to 0.0.21, which is an unusually large increment. Consider documenting major changes in a changelog or comment.


18-34: Improved record matching approach

Good replacement of attributeId with the more descriptive matchingAttribute and matchingAttributeValue props. This makes the record matching logic more explicit and easier to understand.


36-53: Clean prop generation with simpler attribute filtering

The additionalProps method has been simplified to use api_slug instead of attribute.id.attribute_id and to filter only on is_writable. This is a good improvement for maintainability.


104-120: Improved record upsert structure

The revised structure for upsertRecord correctly uses the matching attribute parameters and simplifies the values object construction.

One suggestion: the debug: true flag might be meant for development and should probably be removed in production.

    const response = await attio.upsertRecord({
      $,
-     debug: true,
      objectId,
      params: {
        matching_attribute: matchingAttribute,
      },
components/attio/attio.app.mjs (7)

1-2: Good centralization of constants

Importing constants from a dedicated module is a great practice for maintainability.


8-71: Comprehensive person-related property definitions

Excellent job creating detailed property definitions for person attributes. Each prop has clear labels, descriptions, and appropriate optional flags.


123-153: Fix offset calculations in remaining options functions

The same NaN issue exists in the entryId options function.

          params: {
            limit: constants.DEFAULT_LIMIT,
-           offset: page * constants.DEFAULT_LIMIT,
+           offset: (page ?? 0) * constants.DEFAULT_LIMIT,

170-193: Same NaN issue in attributeId options

The offset calculation in attributeId options should also handle undefined page.

          params: {
            limit: constants.DEFAULT_LIMIT,
-           offset: page * constants.DEFAULT_LIMIT,
+           offset: (page ?? 0) * constants.DEFAULT_LIMIT,

196-204: Clean helper methods for URL and headers

Good refactoring of URL and headers construction into dedicated helper methods for consistency and maintainability.


205-243: Well-structured HTTP request methods

The generic HTTP wrapper methods and API-specific methods are well-structured, promoting code reuse and consistency.


244-303: Good organization of API methods

The API methods are well-organized with consistent parameter destructuring and use of the generic HTTP wrappers.

@jcortes jcortes force-pushed the attio-new-components branch from 8861d86 to f5f1a70 Compare May 2, 2025 22:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
components/attio/attio.app.mjs (3)

97-99: Default page to 0 to avoid NaN offset

In the recordId options method, using page * constants.DEFAULT_LIMIT as the offset can cause issues when page is undefined (which is possible for optional parameters). This will result in a NaN offset value, which could cause API request failures.

-            offset: page * constants.DEFAULT_LIMIT,
+            offset: (page ?? 0) * constants.DEFAULT_LIMIT,

147-149: Default page to 0 to avoid NaN offset

Similar to the issue in the recordId options method, the same problem exists here in the entryId options method.

-            offset: page * constants.DEFAULT_LIMIT,
+            offset: (page ?? 0) * constants.DEFAULT_LIMIT,

181-183: Default page to 0 to avoid NaN offset

The same issue with page being potentially undefined exists in the matchingAttribute options method.

-            offset: page * constants.DEFAULT_LIMIT,
+            offset: (page ?? 0) * constants.DEFAULT_LIMIT,
🧹 Nitpick comments (2)
components/attio/attio.app.mjs (2)

7-195: Consider adding JSDoc comments to prop definitions

While the property definitions have good descriptions, adding JSDoc comments would improve code documentation and provide better IDE support. This would be especially helpful for complex properties with async options.

Example for one property:

+    /**
+     * @property {string} firstName
+     * @description The person's first name
+     * @required
+     */
     firstName: {
       type: "string",
       label: "First Name",
       description: "The person's first name.",
     },

196-304: Consider adding error handling to API methods

The current implementation doesn't include explicit error handling for API requests. Adding try/catch blocks or error handling middleware would improve robustness and provide better error messages to users.

Example implementation:

     async listRecords({
       targetObject, ...args
     } = {}) {
+      try {
         return this.post({
           path: `/objects/${targetObject}/records/query`,
           ...args,
         });
+      } catch (error) {
+        console.error(`Error listing records for ${targetObject}:`, error);
+        throw error;
+      }
     },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8861d86 and f5f1a70.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • components/attio/actions/create-note/create-note.mjs (3 hunks)
  • components/attio/actions/create-person/create-person.mjs (1 hunks)
  • components/attio/actions/create-task/create-task.mjs (1 hunks)
  • components/attio/actions/create-update-record/create-update-record.mjs (2 hunks)
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs (2 hunks)
  • components/attio/actions/update-person/update-person.mjs (1 hunks)
  • components/attio/attio.app.mjs (2 hunks)
  • components/attio/common/constants.mjs (1 hunks)
  • components/attio/common/utils.mjs (2 hunks)
  • components/attio/package.json (1 hunks)
  • components/attio/sources/common/base.mjs (3 hunks)
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs (2 hunks)
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs (2 hunks)
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (1 hunks)
  • components/attio/sources/new-activity-created-instant/test-event.mjs (1 hunks)
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs (2 hunks)
  • components/attio/sources/new-note-instant/new-note-instant.mjs (1 hunks)
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs (1 hunks)
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs (2 hunks)
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs (1 hunks)
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs (1 hunks)
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/attio/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (20)
  • components/attio/package.json
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs
  • components/attio/sources/new-note-instant/new-note-instant.mjs
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs
  • components/attio/sources/new-activity-created-instant/test-event.mjs
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs
  • components/attio/sources/common/base.mjs
  • components/attio/actions/update-person/update-person.mjs
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs
  • components/attio/actions/create-task/create-task.mjs
  • components/attio/actions/create-note/create-note.mjs
  • components/attio/actions/create-person/create-person.mjs
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs
  • components/attio/common/utils.mjs
  • components/attio/actions/create-update-record/create-update-record.mjs
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Lint Code Base
🔇 Additional comments (4)
components/attio/attio.app.mjs (4)

8-71: Well-structured person property definitions

The addition of comprehensive person-related properties with consistent structure and descriptive labels provides a solid foundation for person record operations. The properties follow a logical organization with appropriate optional flags.


72-104: Good implementation of dynamic record options

The recordId property implementation with async options provides a clean way to fetch dynamic dropdown options from Attio. The flexible design with customizable target object, sorting, and mapping is particularly valuable for reusability.


197-205: Good refactoring of URL and header methods

Extracting URL construction and header setting into separate helper methods improves code organization and ensures consistency across API calls. Using constants for base URLs and version paths is a good practice.


215-238: Well-designed HTTP method wrappers

The addition of wrapper methods for HTTP verbs (POST, PATCH, PUT, DELETE) centralizes request logic and provides a clean API for making different types of requests. This refactoring improves code maintainability and reduces duplication.

@jcortes jcortes force-pushed the attio-new-components branch from f5f1a70 to fb0e255 Compare May 5, 2025 13:47
@jcortes
Copy link
Collaborator Author

jcortes commented May 5, 2025

/approve

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
components/attio/attio.app.mjs (1)

127-149: ⚠️ Potential issue

Default page to 0 in entryId options method

The same NaN offset issue exists in the entryId options method when page is undefined.

 async options({
   listId, page,
 }) {
   const { data } = await this.listEntries({
     listId,
     params: {
       limit: constants.DEFAULT_LIMIT,
-      offset: page * constants.DEFAULT_LIMIT,
+      offset: (page ?? 0) * constants.DEFAULT_LIMIT,
     },
   });
♻️ Duplicate comments (3)
components/attio/common/utils.mjs (2)

58-73: ⚠️ Potential issue

Fix context issue in default propsMapper

The default propsMapper function references this which may lead to unexpected behavior when not bound properly.

 function getFieldProps({
   index, fieldName, prefix,
-  propsMapper = function propsMapper(prefix) {
-    const { [`${prefix}name`]: name } = this;
-    return {
-      name,
-    };
-  },
+  propsMapper = (prefix, context) => {
+    const name = context?.[`${prefix}name`];
+    return {
+      name,
+    };
+  },
+  context,
 } = {}) {
   const { prefix: metaPrefix } = getMetadataProp({
     index,
     fieldName,
     prefix,
   });
-  return propsMapper(metaPrefix);
+  return propsMapper(metaPrefix, context);
 }

75-86: 🛠️ Refactor suggestion

Update getFieldsProps to pass context parameter

Since getFieldProps needs to be updated to accept a context parameter, getFieldsProps should also be updated to pass this parameter through.

 function getFieldsProps({
-  numberOfFields, fieldName, propsMapper, prefix,
+  numberOfFields, fieldName, propsMapper, prefix, context,
 } = {}) {
   return Array.from({
     length: numberOfFields,
   }).map((_, index) => getFieldProps({
     index,
     fieldName,
     prefix,
     propsMapper,
+    context,
   }));
 }
components/attio/attio.app.mjs (1)

72-104: ⚠️ Potential issue

Default page to 0 to avoid NaN offset

In the recordId prop's options method, when page is undefined, page * constants.DEFAULT_LIMIT will evaluate to NaN, breaking pagination.

 async options({
   page,
   targetObject = constants.TARGET_OBJECT.COMPANIES,
   sorts = [
     {
       direction: "desc",
       attribute: "created_at",
       field: "value",
     },
   ],
   mapper = ({
     id: { record_id: value },
     values: { name },
   }) => ({
     value,
     label: name[0]?.value || name[0]?.full_name,
   }),
 }) {
   const { data } = await this.listRecords({
     targetObject,
     data: {
       limit: constants.DEFAULT_LIMIT,
-      offset: page * constants.DEFAULT_LIMIT,
+      offset: (page ?? 0) * constants.DEFAULT_LIMIT,
       sorts,
     },
   });
   return data?.map(mapper);
 },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5f1a70 and fb0e255.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • components/attio/actions/create-note/create-note.mjs (3 hunks)
  • components/attio/actions/create-person/create-person.mjs (1 hunks)
  • components/attio/actions/create-task/create-task.mjs (1 hunks)
  • components/attio/actions/create-update-record/create-update-record.mjs (2 hunks)
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs (2 hunks)
  • components/attio/actions/update-person/update-person.mjs (1 hunks)
  • components/attio/attio.app.mjs (2 hunks)
  • components/attio/common/constants.mjs (1 hunks)
  • components/attio/common/utils.mjs (2 hunks)
  • components/attio/package.json (1 hunks)
  • components/attio/sources/common/base.mjs (3 hunks)
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs (2 hunks)
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs (2 hunks)
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs (1 hunks)
  • components/attio/sources/new-activity-created-instant/test-event.mjs (1 hunks)
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs (2 hunks)
  • components/attio/sources/new-note-instant/new-note-instant.mjs (1 hunks)
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs (1 hunks)
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs (2 hunks)
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs (1 hunks)
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs (1 hunks)
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/attio/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (19)
  • components/attio/package.json
  • components/attio/sources/object-attribute-updated-instant/object-attribute-updated-instant.mjs
  • components/attio/sources/new-object-attribute-instant/new-object-attribute-instant.mjs
  • components/attio/sources/list-entry-deleted-instant/list-entry-deleted-instant.mjs
  • components/attio/sources/new-activity-created-instant/test-event.mjs
  • components/attio/sources/note-updated-instant/note-updated-instant.mjs
  • components/attio/sources/new-record-created-instant/new-record-created-instant.mjs
  • components/attio/sources/new-list-entry-instant/new-list-entry-instant.mjs
  • components/attio/sources/list-entry-updated-instant/list-entry-updated-instant.mjs
  • components/attio/actions/update-person/update-person.mjs
  • components/attio/sources/common/base.mjs
  • components/attio/actions/delete-list-entry/delete-list-entry.mjs
  • components/attio/sources/new-note-instant/new-note-instant.mjs
  • components/attio/sources/record-updated-instant/record-updated-instant.mjs
  • components/attio/sources/new-activity-created-instant/new-activity-created-instant.mjs
  • components/attio/actions/create-note/create-note.mjs
  • components/attio/actions/create-task/create-task.mjs
  • components/attio/actions/create-update-record/create-update-record.mjs
  • components/attio/actions/create-person/create-person.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
🔇 Additional comments (14)
components/attio/common/utils.mjs (5)

1-1: Good addition of centralized constants

Importing constants from a dedicated module improves maintainability and consistency across the codebase.


38-41: Good utility function for consistent formatting

The toPascalCase utility function ensures consistent string formatting across the component.


43-56: Well-structured metadata property generator

The getMetadataProp function handles prefix and label generation with good flexibility, making field metadata consistent throughout the application.


88-122: Well-designed asynchronous property generation

The getAdditionalProps function provides a robust way to asynchronously accumulate field property definitions. The approach using reduce with async/await handling is elegant and allows for flexibility in property definition.


127-130: Good export additions

Properly exporting the new utility functions makes them available for use in other modules.

components/attio/attio.app.mjs (9)

2-2: Good addition of centralized constants

Importing constants from a dedicated module improves maintainability and consistency across the component.


8-71: Well-structured person property definitions

The comprehensive set of person-related properties (firstName, lastName, emailAddress, etc.) is well-organized with consistent structure and helpful descriptions.


105-122: Well-structured workspace member properties

The workspaceMemberId property with its asynchronous options method is well-designed and provides a clean interface for selecting workspace members.


151-152: Improved data mapping for entry IDs

The updated mapping for entry IDs properly extracts the entry_id value from the nested id structure.


158-169: Flexible object ID options with filter and mapper

The updated objectId options method now accepts custom filter and mapper functions, providing more flexibility for consumers of this prop.


197-205: Good refactoring of URL and header generation

The creation of getUrl and getHeaders helper methods improves code organization and maintainability by centralizing these common operations.


206-214: Improved request method with better parameter handling

The refactored _makeRequest method now uses object destructuring and properly combines arguments, making it more flexible and maintainable.


215-238: Well-structured HTTP method wrappers

The HTTP method wrappers (post, patch, put, delete) provide a clean, consistent interface for making API requests and properly delegate to the core _makeRequest method.


239-304: Comprehensive API method implementations

The implementation of various API methods (listWorkspaceMembers, listRecords, etc.) with consistent parameter handling and proper delegation to HTTP methods is well-structured and maintainable.

@jcortes jcortes force-pushed the attio-new-components branch from fb0e255 to ef5b37d Compare May 5, 2025 14:03
@jcortes
Copy link
Collaborator Author

jcortes commented May 5, 2025

/approve

@jcortes jcortes force-pushed the attio-new-components branch from ef5b37d to a528d04 Compare May 5, 2025 20:09
@jcortes jcortes merged commit aae9f1c into master May 5, 2025
11 checks passed
@jcortes jcortes deleted the attio-new-components branch May 5, 2025 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Components] attio
2 participants